#include <system.h>

#define PT_Num_Entries 1024

#define PTAttrPresent 0x00000001
#define PTAttrReadWrite 0x00000002
#define PTAttrUser 0x00000004
#define PTAttrWriteThrough 0x00000008
#define PTAttrCacheDisabled 0x00000010
#define PTAttrAccessed 0x00000020
#define PTAttrDirty 0x00000040
#define PTAttrZero 0x00000080
#define PTAttrGlobal 0x00000100
#define PTPageAdrMask 0xFFFFF000

#define PD_Num_Entries 1024

#define PDAttrPresent 0x00000001
#define PDAttrReadWrite 0x00000002
#define PDAttrUser 0x00000004
#define PDAttrWriteThrough 0x00000008
#define PDAttrCacheDisabled 0x00000010
#define PDAttrAccessed 0x00000020
#define PDAttrZero 0x00000040
#define PDAttrSize 0x00000080
#define PDAttrGlobal 0x00000100
#define PDPageAdrMask 0xFFFFF000


unsigned int mem_map[mem_map_num_entries];
int mem_usedblocks = 0;
int memsearchstart = 0;

void** kernelPD;

void mmgr_install()
{
 memset(&mem_map,0,mem_map_size);
 // Mark the kernel space as used
 asm volatile("xchg %bx, %bx");
 asm volatile(
  "sub $0xC0000000, %%eax;" // ((((&end-Higher_Half_Address)...
  "shr $12, %%eax;" // .../mem_block_size)...
  "add $1, %%eax;" // ...+1)...
  "shr $3, %%eax;" // .../8)...
  "add $2, %%eax" // ...+2
 : "=a"(mem_usedblocks) : "a"(&end));
 memset(&mem_map,0xFF,mem_usedblocks);
}

unsigned char* memcpy(unsigned char* dest, const unsigned char* src, int count)
{
 const char* sp = src;
 char* dp = dest;
 for(; count != 0; count--) *dp = *sp, dp++, sp++;
 return dest;
}

unsigned char* memmove(unsigned char* dest, const unsigned char* src, int count)
{
 if(dest > src)
 {
  const char* sp = src;
  char* dp = dest;
  for(; count > 0; count--)
   *dp = *sp, dp++, sp++;
 }else{
  const char* sp = src + count;
  char* dp = dest + count;
  for(; count > 0; count--)
   *dp = *sp, dp--, sp--;
 }
 return dest;
}

unsigned char* memset(unsigned char* dest, unsigned char val, int count)
{
 char* dp = dest;
 for(; count != 0; count--) *dp = val, dp++;
 return dest;
}

unsigned short* memsetw(unsigned short* dest, unsigned short val, int count)
{
 for(; count > 0; count--)
  dest[count] = val;
 return dest;
}

int strlen(const char* str)
{
 int i = 0;

 while(str[i] != 0) i++;
 return i;
}

void mem_displaymapvga()
{
 int x = 0;
 int y = 0;

 for(; y < 24;)
 {
  int bits, i, j;
  for(bits = i = 0; i < 16; i++)
   for(j = 0; j < 32; j++)
    if(mem_map[(((y*80)+x)*16)+i] & (1 << j)) bits++;
  vga_settextcolor((bits-1)/32,0);
  vga_setsquare('-',x,y);
  if(x > 78) x = 0, y++;
  else x++;
 }

 vga_setcursor(0,24);
 vga_settextcolor(0xF,0);
 int i;
 for(i = 0; i < 80; i++)
  vga_printstr(" ");

 char str[33];

 itoa(&str,mem_usedblocks,10);
 vga_setcursor(0,24);
 vga_printstr(&str);

 itoa(&str,memsearchstart,10);
 vga_setcursor(16,24);
 vga_printstr(&str);
}

void* mem_findblock()
{
 if(mem_usedblocks >= mem_num_blocks) return 0;

 int i = memsearchstart, j;

 while(i < mem_map_num_entries)
 {
  if(mem_map[i] != 0xFFFFFFFF)
  {
   for(j = 0; j < 32; j++)
   {
    if(!(mem_map[i] & (1 << j)))
    {
     mem_usedblocks++;
     mem_map[i] = mem_map[i] | (1 << j);
     memsearchstart = ((i >= mem_map_num_entries-1) ? 0 : i);
     return ((i*32)+j)*mem_block_size;
	 i = mem_map_num_entries, j = 32;
    }
   }
  }
  i++;
  if(i >= mem_map_num_entries) i = 0;
  if(i == memsearchstart) i = mem_map_num_entries;
 }

 return 0;
}

void mem_freeblock(void* p)
{
 int b = (unsigned int)p >> 12;
 mem_map[b/32] &= ~(1 << (b%32));
 mem_usedblocks--;
}